~ 運籌帷幄之中,決勝於千里之外 ~
相關程式碼:https://github.com/slindevel/modern-aws-marathon
虛擬化讓我們能在文件腳本中定義資源,即基礎設施及代碼(Infrastructure as Code,IaC)
CloudFormation 能幫助您模型化與設定 AWS 資源的服務。我們建立一個描述所有所需之 AWS 資源的範本 (如 Amazon EC2 執行個體或 Amazon RDS 資料庫執行個體),而 CloudFormation 負責為您佈建與設定這些資源。
這個服務中有兩大重要名詞:
我們先來看一段官方的 workshop 裡的定義:
An AWS CloudFormation template is a declaration of the AWS resources that make up a stack.
template 他是一種資源的**「宣告」,雖然說是用代碼寫資源配置,感覺上是比較偏向「靜態」定義資源**。
接著我們來解析一下 template 的文件,yaml & json 格式最大的差別在於yaml可以加上註釋,所以之後的說明我們都以 yaml 格式為主,比較好解說,另外 yaml 的文件看的時候要注意 「縮排」 & 「階層」,json ↔ yaml 是可以互轉的喔!
我們先從 yaml 文件的 Top-Level objects 開始:
AWSTemplateFormatVersion: 'version date' (optional) # version of the CloudFormation template. Only accepted value is '2010-09-09'
Description: 'String' (optional) # a text description of the Cloudformation template
Metadata: 'template metadata' (optional) # objects that provide additional information about the template
Parameters: 'set of parameters' (optional) # a set of inputs used to customize the template
Rules: 'set of rules' (optional) # a set of rules to validate the parameters provided at deployment/update
Mappings: 'set of mappings' (optional) # a mapping of keys and associated values
Conditions: 'set of conditions' (optional) # conditions that control whether certain resources are created
Transform: 'set of transforms' (optional) # for serverless applications
Resources: 'set of resources' (required) # a components of your infrastructure
Hooks: 'set of hooks' (optional) # Used for ECS Blue/Green Deployments
Outputs: 'set of outputs' (optional) # values that are returned whenever you view your stack's properties
讓我們一個個來看看:
AWSTemplateFormatVersion: '2010-09-09'
Description: A simple queue for the demo purpose
# Day4/cfn-s3-demo.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Create S3 Bucket named 'slin-cfn-s3-demo'
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: slin-cfn-s3-demo
VersioningConfiguration:
Status: Enabled
# cloudformation stack name: cf-s3-demo
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-demo.yaml \
--capabilities CAPABILITY_IAM
$ aws cloudformation delete-stack --stack-name cf-s3-demo. #記得清除資源
# Day4/cf-s3-parameters-demo.yaml
# aws cloudformation create-stack \
# --stack-name cf-s3-demo \
# --template-body file://Day4/cf-s3-parameters-demo.yaml \
# --capabilities CAPABILITY_IAM
AWSTemplateFormatVersion: 2010-09-09
Description: Create S3 Bucket named 'slin-cf-s3-demo'
Parameters:
BucketName:
# Default: slin-cf-s3-demo
Type: String
Description: 'A bucket name to set.'
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Ref BucketName
VersioningConfiguration:
Status: Enabled
# output:
# An error occurred (ValidationError) when calling the CreateStack operation:
# Parameters: [BucketName] must have values
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-parameters-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo
$ aws s3 ls #檢查s3 bucket slin-cf-s3-demo 是否建立
$ aws cloudformation delete-stack --stack-name cf-s3-demo. #記得清除資源
# Day4/cf-s3-outputs-demo.yaml
...
Outputs: #add to the tail
MyStacksRegion:
Value: !Ref 'AWS::Region'
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-parameters-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo
$ aws cloudformation describe-stacks --stack-name cf-s3-demo --query "Stacks[].Outputs"
[
[
{
"OutputKey": "BucketARN",
"OutputValue": "arn:aws:s3:::slin-cf-s3-demo",
"Description": "The ARN of the bucket."
},
{
"OutputKey": "MyStacksRegion",
"OutputValue": "ap-northeast-1"
}
]
]
$ aws cloudformation delete-stack --stack-name cf-s3-demo #記得清除資源
Mappings:
Mapping01:
TopLevelKey01:
SecondLevelKey01: Value01
SecondLevelKey02: Value02
TopLevelKey02:
SecondLevelKey01: Value03
SecondLevelKey02: Value04
...
# Day4/cf-s3-mappings-demo.yaml
Parameters:
...
Environment:
Type: String
AllowedValues:
- Dev
- Test
- Prod
Description: 'Select an environment.'
Mappings:
EnvironmentToBucketSuffix:
Dev:
Suffix: 'this-is-dev'
Test:
Suffix: 'use-only-for-testing'
Prod:
Suffix: 'be-careful-it-is-production'
...
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-mappings-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
ParameterKey=Environment,ParameterValue=foobar
An error occurred (ValidationError) when calling the CreateStack operation: Parameter 'Environment' must be one of AllowedValues
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-mappings-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
ParameterKey=Environment,ParameterValue=Dev
$ aws s3 ls
...
2023-08-13 00:07:33 slin-cf-s3-demo-this-is-dev
...
# Day4/cf-s3-conditions-demo.yaml
...
Conditions:
isProduction: !Equals [ !Ref Environment, Prod]
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !If [ isProduction, slin-cf-s3-prod, slin-cf-s3-demo ]
VersioningConfiguration:
Status: Enabled
...
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-conditions-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
ParameterKey=Environment,ParameterValue=Prod
$ aws s3 ls
...
2023-08-13 00:29:16 slin-cf-s3-prod
...
$ aws cloudformation delete-stack --stack-name cf-s3-demo #delete stack again
$ aws cloudformation create-stack \
--stack-name cf-s3-demo \
--template-body file://Day4/cf-s3-conditions-demo.yaml \
--capabilities CAPABILITY_IAM \
--parameters ParameterKey=BucketName,ParameterValue=slin-cf-s3-demo \
ParameterKey=Environment,ParameterValue=Dev
$ aws s3 ls
...
2023-08-13 00:38:26 slin-cf-s3-demo
...
AWS CloudFormation 提供多個內建函數,可協助您管理您的堆疊。在範本中使用內部函數,將值指派給要到執行時間才能使用的屬性。 ~ by AWS ~
我們直接從一個簡單的範例來看看這些內部函數如何使用,這個範例會建立一個 EC2 Instance,使用到了兩個內置函數:
最後會在 EC2 看到 name:t2.micro-webserver 的 Instance
# Day4/cf-intrinsic-functions.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: AWS CloudFormation Intrinsic functions Sample
Parameters:
InstanceType:
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.small
Description: 'Enter t2.micro or t2.small. Default is t2.micro.'
AmiID:
Type: AWS::EC2::Image::Id
Description: 'The ID of the AMI.'
# Add AmiId parameter here
Resources:
WebServerInstance:
Type: AWS::EC2::Instance
Properties:
# Use !Ref function in ImageId property
ImageId: !Ref AmiID
InstanceType: !Ref InstanceType
Tags:
- Key: Name
Value: !Join [ '-', [ !Ref InstanceType, webserver ] ]
執行看看,其中 AmiID 需要用指令查詢,這個 AmiID是會變動的唷
ParameterValue 要帶入查詢到的 AmiID
AmiID 指的是 Amazon Machine Image,AWS 虛擬機器映像檔
$ aws cloudformation create-stack \
--stack-name cf-day4-intrinsic-functions
--template-body file://Day4/cf-intrinsic-functions.yaml
--parameters ParameterKey="AmiID",ParameterValue=<AmiId>
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:<AccountId>:stack/cf-day4-intrinsic-functions/d5fa02b0-4e61-11ee-91ec-067eb25769dd"
}
# query statck status
$ aws cloudformation describe-stacks --stack-name cf-day4-intrinsic-functions
# clean up resource
$ aws cloudformation delete-stack --stack-name cf-day4-intrinsic-functions
如何查詢 AMI ID ?
$ aws ec2 describe-images --owners self amazon
{
"Images": [
{
"Architecture": "x86_64",
"CreationDate": "2022-11-14T23:19:27.000Z",
"ImageId": "ami-07b14acc0c4d11fcc",
"ImageLocation": "amazon/amzn2-ami-minimal-hvm-2.0.20221103.3-x86_64-ebs",
"ImageType": "machine",
"Public": true,
"OwnerId": "137112412989",
"PlatformDetails": "Linux/UNIX",
"UsageOperation": "RunInstances",
"State": "available",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xvda",
"Ebs": {
"DeleteOnTermination": true,
"SnapshotId": "snap-016aca1439d9dc407",
:
到這裡為止,是否對 cloudformation 上手了呢,AWS 官方有提供一個 github 裡面有各式各樣的可以參考的 template ,網址是:https://github.com/awslabs/aws-cloudformation-templates.git
筆者認為現在比較流行的 IaC 是使用 terraform 或是 AWS CDK,CDK 不用說 DevOps 專門
CloudFormation 與 Terreform 各有優缺點,兩者通常會交互使用,尤其是 Terreform 可以跨雲部署道路是更寬廣了
參考資料:
https://blog.awsfundamentals.com/infrastructure-as-code-on-aws-an-introduction
https://blog.awsfundamentals.com/infrastructure-as-code-on-aws-an-introduction
https://docs.aws.amazon.com/zh_tw/AWSCloudFormation/latest/UserGuide/Welcome.html
https://catalog.workshops.aws/cfn101/en-US/basics/templates/template-anatomy
https://keshavbist.com.np/anatomy-of-aws-cloudformation-templates
https://rickhw.github.io/2017/03/31/AWS/Study-Notes-CloudFormation-Template-Anatomy/
https://godleon.github.io/blog/AWS/AWS-SOA-CloudFormation/